home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1997 May
/
EnigmA AMIGA RUN 18 (1997)(G.R. Edizioni)(IT)[!][issue 1997-05][EAR-CD II].iso
/
softwareupdate
/
system
/
amigados
/
advancedroutines
/
advancedroutines.doc
next >
Wrap
Text File
|
1996-10-10
|
29KB
|
914 lines
7 ADVANCED ROUTINES
7.1 INTRODUCTION
In this chapter I will describe some advanced routines in
AmigaDOS. Although this chapter is mainly intended for
experienced programmers I have tried to make it as easy as
possible to read even if you are new C programmer and have
not worked so much with AmigaDOS.
7.2 GET INFORMATION ABOUT FILES AND DIRECTORIES
In some occations you might need to get some information about
a file or directory. You might want to see which protection
bits are currently set, how big the it is, on what date it was
created, what comment is attached and so on... To get this type
of information you should use the "Examine()" function.
Examine() allows you to examine files, directories and volumes.
In the following sections I will now and then refer to all of
these types as "objects".
There are two things you have to do before you can call
Examine():
1. You must lock the object you want to examine. Simply use
the Lock() function as previously explained.
2. Create a FileInfoBlock structure. The problem with this
structure is that it is used by AmigaDOS directly and must
therefore be long word aligned! (Since you have to create
the structure you must make sure that it is long word
aligned. Structures that are created by AmigaDOS itself
will always be long word aligned.)
7.2.1 LOCK THE OBJECT
First you have to lock the object you want to examine with help
of the Lock() function. Since we will only examine the object
(read some values) it is enough with a shared lock ("read
lock").
Here is an example:
/* A "BCPL" pointer to our lock: */
BPTR my_lock;
- - -
/* Try to lock the object we later will examine: */
my_lock = Lock( "RAM:Highscore.dat", SHARED_LOCK );
/* Check if we have successfully locked the object or not: */
if( my_lock == NULL )
printf( "Could not lock the object!\n" );
7.2.2 CREATE A FILE INFO BLOCK
Before we can call Examine() we must also create a
FileInfoBlock structure. This structure must, as already
explained, be long word aligned ("a present from the wonderful
BCPL language"). How we should create this structure depends
on if your program should be compatible with the old dos
libraries (WB1.2 and WB1.3) or not.
7.2.2.1 OLD DOS VERSIONS (WB1.3 OR WB1.2)
If your program should be able to run on the old systems (dos
libraries older than V37) you should allocate the
FileInfoStructure with help of the AllocMem() function.
Here is an example:
/* Declare a pointer to a FileInfoBlock structure: */
struct FileInfoBlock *my_fib_ptr;
- - -
/* Allocate enough memory for a FileInfoBlock structure: */
/* (OK! This memory will be long word aligned.) */
my_fib_ptr = (struct FileInfoBlock *)
AllocMem( sizeof( struct FileInfoBlock ), MEMF_ANY | MEMF_CLEAR );
/* Check if we have allocated the memory successfully: */
if( my_fib_ptr == NULL )
printf( "Could not allocate enough memory!\n" );
7.2.2.2 NEW RELEASE 2 (WB2.04) OR HIGHER
If your program only should be used on systems with dos library
V37 or higher (WB2.04 or higher) you should use the new
AllocDosObject() function which is defined like this:
---------------------------------------------------------------
AllocDosObject()
ROM library: "dos.library/AllocDosObject", (V37+)
#include <clib/dos_protos.h>
Allocates different types of objects used by AmigaDOS. The
objects will be long word aligned, and the size can vary
between different dos library releases.
Synopsis: object = AllocDosObject( type, tags );
object: (APTR) The function will return a pointer to the new
allocated object, or NULL if the object could not be
created.
types: (ULONG) The type of object you want to allocate:
(defined in header file "dos/dos.h")
DOS_FIB FileInfoBlock structure.
DOS_FILEHANDLE When you want to create your own
file handler. Rarely used.
DOS_EXALLCONTROL To create an object used by the
ExAll() function. (See below for
more information)
DOS_STDPKT When you want a "standard AmigaDOS
Packets".
DOS_CLI Object needed when you write
your own Shells.
DOS_RDARGS Used by the command line parsing
routines as described in chapter 5
"Parsing the Command Line".
tags: (struct TagItem *) Pointer to a list of one or more
TagItem structures which has been initialized with
your requirements, or NULL if you do not want to set
any tags.
This tag filed is currently only used when you write
your own file handlers or Shells. The available tags
are listed in header file "dos/dos.h", but since they
are rarely used with this function I have not listed
them here. As always the last "Tag ID" must be
"TAG_DONE".
Since this function uses the new "Tag Sytem" there exist two
other options on how to call the function:
Synopsis: object = AllocDosObjectTagList( type, tags );
This one is identical to the "AllocDosObject()" function
which we have just described. See above for information about
the arguments.
Synopsis: object = AllocDosObjectTags( type, tag1, tag2, ... );
Similar to "AllocDosObject()", but instead of giving the
function a pointer to a list of TagItem structures you list
all tags as arguments for the function. Note that the last
"Tag ID" must as always be "TAG_DONE".
tag1: (ULONG) The ID for tag 1.
tag2: (ULONG) The Data for tag 1.
tag3: (ULONG) The ID for tag 2.
- - - and so on...
tagX: (ULONG) The ID for tag X, must be "TAG_DONE".
Note! All objects which are allocated with help of the
AllocDosObject() function must when not needed any more be
deallocated with help of the FreeDosObject() function.
Here is a simple example on how to use the AllocDosObject()
function:
/* Declare a pointer to our FileInfoBlock */
/* which we will allocate: */
struct FileInfoBlock *my_fib;
- - -
/* Create a FileInfoBlock structure with help */
/* of the new AllocDosObject() function: */
my_fib = AllocDosObject( DOS_FIB, NULL );
/* Check if we have allocated the memory successfully: */
if( !my_fib )
printf( "Could not allocate the FileInfoBlock!\n" );
See also: Examine(), FreeDosObject()
---------------------------------------------------------------
7.2.3 CALL EXAMINE()
Once you have locked the object you want to examine and you
have allocated a FileInfoBlock structure you may call the
Examine() function.
---------------------------------------------------------------
Examine()
ROM library: "dos.library/Examine", (All versions)
#include <clib/dos_protos.h>
Examines a file, direcotry, volume (or device) and stores some
interesting information about the object in a given
FileInfoBlock structure.
Synopsis: ok = Examine( lock, fib );
ok: (LONG) If the function managed to examine the object
it returns "DOSTRUE". On the other hand, if the
function failed to get the information it returns
"DOSFALSE".
lock: (BPTR) A BCPL pointer to the lock on the object you
want to examine.
fib: (struct FileInfoBlock *) Pointer to a FileInfoBlock
structure in which all information will be stored.
This structure must be long word aligned.
Here is a simple example on how to use the Examine() function:
/* AmigaDOS boolean check variable: */
LONG ok;
- - -
/* Get some information about an object: */
ok = Examine( my_lock, my_fib );
/* Could we get the information? */
if( !ok )
printf( "Error! Could not examine the object!\n" );
else
printf( "OK! You may examine the FileInfoBlock structure" );
See also: AllocDosObject(), AllocMem(), ExNext(),
FreeDosObject()
---------------------------------------------------------------
7.2.4 EXAMINE THE FILE INFO BLOCK
If you have successfully examined the object you may look at
the different fields in the FileInfoBlock structure. The
structure is defined in header file "dos/dos.h" like this:
struct FileInfoBlock
{
LONG fib_DiskKey;
LONG fib_DirEntryType;
char fib_FileName[108];
LONG fib_Protection;
LONG fib_EntryType;
LONG fib_Size;
LONG fib_NumBlocks;
struct DateStamp fib_Date;
char fib_Comment[80];
char fib_Reserved[36];
};
fib_DiskKey: Key number for the disk. Usually of no
interest for us.
fib_DirEntryType: If the number is smaller than zero it is a
file. On the other hand, if the number is
larger than zero it is a directory (or volume
or device).
/* Is it a file or directory (etc)? */
if( my_fib->fib_DirEntryType < 0 )
printf( "File\n" );
else
printf( "Directory or Volume\n" );
fib_FileName: Null terminated string containing the file-
name. (File names may not be longer than 30
characters.)
fib_Protection: Field containing the protection flags:
(if set)
FIBF_DELETE : the file/directory can not be
deleted.
FIBF_EXECUTE : the file can not be executed.
FIBF_WRITE : you can not write to the file.
FIBF_READ : you can not read the file.
FIBF_ARCHIVE : Archive bit.
FIBF_PURE : Pure bit.
FIBF_SCRIPT : Script bit.
/* Is the object protected: */
if( my_fib->fib_Protection & FIBF_DELETE )
printf( "Protected!" );
else
printf( "Not protected!" );
fib_EntryType: File/Directory entry type number. Usually of no
interest for us.
fib_Size: Size of the file (in bytes).
fib_NumBlocks: Number of blocks in the file.
fib_Date: Structure containing the date when the file
was latest updated/created. See below for
more information.
fib_Comment: Null terminated string containing a comment.
(Max 80 characters including the NULL sign.)
fib_Reserved: This field is for the moment reserved, and may
therefore not be used.
The DateStamp structure which is a part of the FileInfoBlock
structure is also defined in header file "dos/dos.h", and looks
like this:
struct DateStamp
{
LONG ds_Days;
LONG ds_Minute;
LONG ds_Tick;
};
ds_Days: Number of days since 01-Jan-1978.
ds_Minute: Number of minutes past midnight.
ds_Tick: Number of ticks past the last minute. There are 50
ticks / second. (50 * 60 = 3000 ticks / minute.)
See the examples for a complete list of how to examine the
FileInfoBlock structure.
7.2.5 CLEAN UP
Once you have examined the FileInfoBlock structure and do not
want to use it any more you should deallocate it. If you
allocated it with help of AllocMem() you must free it with help
of FreeMem():
/* Deallocate the memory when we do not need it any more: */
FreeMem( my_fib_ptr, sizeof( struct FileInfoBlock ) );
However, if you allocated the structure with help of the new
AllocDosObject() function you have to use the FreeDosObject()
function to deallocate the structure. The FreeDosObject()
function is defined like this:
---------------------------------------------------------------
FreeDosObject()
ROM library: "dos.library/FreeDosObject", (V37+)
#include <clib/dos_protos.h>
Deallocates objects that was created by a previous call to the
AllocDosObject() function.
Synopsis: FreeDosObject( type, tags );
types: (ULONG) The type of object that should be
deallocated: (You must of course use the same type
as when you allocated the object. See function
AllocDosObject() for more information about the
available types.)
DOS_FIB
DOS_FILEHANDLE
DOS_EXALLCONTROL
DOS_STDPKT
DOS_CLI
DOS_RDARGS
object: (APTR) Pointer to the object that should be
deallocated.
Note! All objects which are allocated with help of the
AllocDosObject() function must when not needed any more be
deallocated with help of this FreeDosObject() function.
Note! Only objects which were created by AllocDosObject() may
be deallocated with this function.
Here is a simple example on how to use the FreeDosObject()
function:
- - -
/* Deallocate the FileInfoBlock structure wich we have */
/* created with help of the AllocDosObject() function: */
FreeDosObject( DOS_FIB, my_fib );
See also: AllocDosObject(), Examine()
---------------------------------------------------------------
You must of course also unlock the object when you do not need
it any more. Example:
/* Unlock the object: */
UnLock( my_lock );
7.3 EXAMINE FILES/SUBDIRECTORIES IN A DIRECTORY/DEVICE
A directory, volume or device (I will refer to them all as
"directories") can contain several files as well as several
(sub)directories. If you want to examine all objects in a
directory you should first use the Examine() function to
examine the directory.
If you discover that the current object is a directory you
can use a function called ExNext() to get information about
the objects in the directory. The first time you call ExNext()
you will get information about the first object in the
directory. You can then call ExNext() again to get information
about the next object and so on until there are no more objects
left to examine and the ExNext() function fails.
It it important to remember that ExNext() can only be called
after you first have successfully called Examine(), and you
must use the same FileInfoBlock structure each time.
The ExNext() function is very similar to Examine() and is
defined like this:
---------------------------------------------------------------
ExNext()
ROM library: "dos.library/ExNext", (All versions)
#include <clib/dos_protos.h>
Examines objects in a directory, device, or volume. Can be
called several times until there are no more objects to
examine.
Synopsis: ok = ExNext( lock, fib );
ok: (LONG) If the function managed to examine the object
it returns "DOSTRUE". On the other hand, if the
function failed to get the information it returns
"DOSFALSE".
When this function fails you should call the IoErr()
function to get more information about the error. If
IoErr() returns "ERROR_NO_MORE_ENTRIES" there were
simply no more objects in the directory (device/
volume), but if IoErr() returns anything else there
was some sort of "real" error.
lock: (BPTR) A BCPL pointer to the lock you used when you
first called Examine().
fib: (struct FileInfoBlock *) Pointer to a FileInfoBlock
structure in which all information will be stored.
This structure must be long word aligned, and you
may not alter any of the fields while you are
collecting objects. You may only read the values,
not modify them!
After you have successfully examined a directory, device or
volume with help of the Examine() function you can use this
function to get information about the objects in that
directory, device or volume. To examine all objects simply
call this function over and over again until it fails because
there are no more objects left to examine, or there was some
sort of error.
Here is a simple example on how to use the ExNext() function:
(You must of course first have called the Examine() function
and checked that it really is a directory (device or volume)
before you may call ExNext().)
- - -
/* As long as we find objects we stay in the loop and */
/* prints the name of the objects we find: */
while( ExNext( my_lock, my_fib ) )
printf( "%s\n", my_fib->fib_FileName );
/* The ExNext() function has now failed. Check if it simply */
/* was no more objects left to examine or if there really */
/* was an error: */
if( IoErr() == ERROR_NO_MORE_ENTRIES )
printf( "OK! No more files!\n" );
else
printf("Error while reading!\n");
See also: Examine()
---------------------------------------------------------------
7.4 GET INFORMATION ABOUT A DISK
To get information about a disk you must first create an
"InfoData" structure in which all information will be stored.
As you probably already have guessed this structure must be
long word aligned. Once you have created the structure you
should lock the disk you want to examine and finally call
the "Info()" function.
7.4.1 CREATE THE INFODATA STRUCTURE
Since the InfoData structure has to be long word aligned you
have to use AllocMem() to create it. (AllocDosObject() does not
support this type of object.)
Here is an example:
/* Declare a pointer to our */
/* info data block: */
struct InfoData *my_info_data;
- - -
/* Allocate memory for an InfoData structure: */
my_info_data = (struct InfoData *)
AllocMem( sizeof( struct InfoData ), MEMF_ANY );
/* Have we successfully allocated the memory? */
if( !my_info_data )
printf( "Could not allocate enough memory!\n" );
7.4.2 LOCK THE DISK
Once you have created an InfoData structure you should lock
the disk you want to examine. (Of course the order does not
matter and you could equally well have first locked the disk
and then allocated the InfoData structure.) Since we will only
look at the disk it is enough with a shared lock.
Here is an example:
/* A "BCPL" pointer to our lock: */
BPTR my_lock;
- - -
/* Lock the disk (in this case "df0:"): */
my_lock = Lock( "df0:", SHARED_LOCK );
/* Have we successfully locked the disk? */
if( !my_lock )
printf( "Could not lock the disk!\n" );
7.4.3 CALL THE INFO() FUNCTION
At last we can call the Info() function to examine the disk.
The Info() function is defined like this:
---------------------------------------------------------------
Info()
ROM library: "dos.library/Info", (All versions)
#include <clib/dos_protos.h>
Examines a disk and stores some interesting information about
it in an InfoData structure.
Synopsis: ok = Info( lock, info );
ok: (LONG) If the function managed to examine the disk
it returns "DOSTRUE". On the other hand, if the
function failed to get the information it returns
"DOSFALSE".
lock: (BPTR) A BCPL pointer to a lock on the disk you want
to examine.
info: (struct InfoData *) Pointer to an InfoData structure
which will be used to store all information in.
Please note that since you have to supply this
function with your own structure is must be long
word aligned!
Here is a simple example on how to use the Info() function:
/* If the function was successful or not: */
LONG ok;
- - -
/* Examine the disk: */
ok = Info( my_lock, my_info_data );
if( ok )
{
/* Print some info about the disk: */
if( my_info_data->id_DiskState == ID_WRITE_PROTECTED )
printf( "The disk is Write Protected!\n" );
if( my_info_data->id_DiskState == ID_VALIDATED )
printf( "The disk is Not (Write) Protected!\n" );
}
else
printf( "Could not examine the disk!\n" );
See also: AllocMem(), Lock()
---------------------------------------------------------------
7.4.4 INFODATA STRUCTURE
If you have successfully called the Info() function you can
start to examine the fields in the InfoData structure which has
now been initialized. The InfoData structure is defined in
header file "dos/dos.h" like this:
struct InfoData
{
LONG id_NumSoftErrors;
LONG id_UnitNumber;
LONG id_DiskState;
LONG id_NumBlocks;
LONG id_NumBlocksUsed;
LONG id_BytesPerBlock;
LONG id_DiskType;
BPTR id_VolumeNode;
LONG id_InUse;
};
id_NumSoftErrors: Number of soft errors on the disk. (Number
of damaged areas.)
id_UnitNumber: In which unit the disk is in. (Note that it
might have been removed after you have called
the Info().)
id_DiskState: The disk can have one of the following three
different states:
ID_VALIDATING The disk has just been
inserted and AmigaDOS is
trying to see what type of
disk it really is. (This
flag can also be set if
the disk is damaged, or
there are internal problems
in the filing system.)
The disk can for the
moment not be used when
it is in this state.
ID_VALIDATED The disk has been
validated, and the disk
is NOT write protected.
ID_WRITE_PROTECTED The disk has been
validated, and the disk
is write protected.
id_NumBlocks: Number of blocks on the disk.
id_NumBlocksUsed: Number of blocks used.
id_BytesPerBlock: Size (in bytes) of each block.
id_DiskType: There exist several different types of disks:
ID_NO_DISK_PRESENT No disk in the drive.
(Interesting type of disk.)
ID_UNREADABLE_DISK The disk contains corrupted
data and can not be used.
ID_DOS_DISK It is a normal disk.
ID_FFS_DISK The disk is using the
"Fast Filing System" (FFS)
ID_INTER_DOS_DISK It is a normal int. disk.
ID_INTER_FFS_DISK The int. disk is using the
"Fast Filing System" (FFS)
ID_NOT_REALLY_DOS Not a dos (normal) disk.
ID_KICKSTART_DISK It is a "Kickstart" disk.
Special type of disk used
on A1000 to load the
system which is on the
other Amiga models included
in the Kickstart ROMs.
ID_MSDOS_DISK It is an (IBM) MS dos
disk. (The special program
"CrossDos" which is
included with WB 2.1 allows
the user to also work with
MS dos disks - 720 kB.)
id_VolumeNode: Pointer to the volume node list which is
rarely used.
id_InUse: If this field is non zero ths disk is in use.
(Since you must have locked the disk before
you could examine it, this field will always
be non zero since at least your program is
using the disk.)
7.5 THE INTERNAL ASSIGN, VOLUME AND DEVICE LIST
AmigaDOS has a list of all Assigns, Volumes and Devices it
currently knows about. Whenever a disk is inserted or removed,
a new assign is added etc... this list is automatically
updated.
As a programmer you migh need to know which assigns, volumes or
devices are currently available. A file requester should for
example be able to display this list so the user can directly
select the device, assign or volume he/she wants to go to.
If you want to get the names of all objects AmigaDOS currently
knows about, and you want your program to be compatible with
all dos library versions, you have to go deep down into the
system. However, as long as you know what you are doing (or
follows my steps carefully) there is danger and we are not
breaking any "programming laws" by doing this.
This is what you have to do:
1. Get a pointer to the dos library. We simply declare the
global dos library pointer as external, and it will
automatically be initialized for us as explained earlier.
/* Declare an external global library */
/* pointer to the Dos library: */
extern struct DosLibrary *DOSBase;
2. In the DosLibrary structure you will find a pointer to
a "RootNode" structure. This strucure contains some
fundamental parts of AmigaDOS but shold not be used
unless you really know what you are dowing.
/* Declare a pointer to the RootNode structure: */
struct RootNode *rootnode_ptr;
- - -
/* Get a pointer to the RootNode structure: */
rootnode_ptr = DOSBase->dl_Root;
3. In the RootNode structure we can find a BCPL pointer to
a DosInfo structure.
/* Declare a temporary BCPL pointer used */
/* to convert BPTRs into C pointer with: */
BPTR temp_bptr;
- - -
/* Get a BCPL pointer (BPTR) to */
/* the DosInfo structure: */
temp_bptr = rootnode_ptr->rn_Info;
4. Since you got a BPTR (a BCPL pointer) you must convert it
into a normal C pointer before you can use it. (BCPL
pointers are four times "smaller" than normal C pointers
and it must therefore be multiplied by 4, which is done
with help of the BADDR() macro.)
/* Declare a pointer to a DosInfo structure: */
struct DosInfo *dos_info_ptr;
- - -
/* Convert the BCPL pointer into a normal C pointer: */
dos_info_ptr = (struct DosInfo *) BADDR( temp_bptr );
5. It is in this DosInfo structure you will find a linked
list of "DosList" nodes. In each DosList node you will
find the name of one device, assign or volume. However,
before you may scan the linked list you have to "lock" it
so it does not change while you are reading it. If the
user inserts or removes a disk for example the list will
be rebuilt and nodes may be added or taken away, and this
must of course not happen while you are in the middle of
the linked list!
On the older dos libraries, prior to V36, there does not
exist any function to directly lock the list. Instead you
have to use the system function "Forbid()" which will turn
off some parts of the multitasking. (Note that while you
are in this "forbidden" mode you may not use any Wait()
calls, and you should as quickly as possible return to
normal state.)
/* Turn off parts of the multitasking: */
Forbid();
6. You can now scan the list of "DosList" nodes. Each DosList
node (structure) has a pointer to the next node. In the
last node this pointer is pointing NULL. (Note that while
you are examining the nodes you have to convert a lot
of BCPL pointers into normal C pointers.)
/* Decalre pointer to the first DosList structure: */
struct DosList *first_doslist_node;
/* Decalre a pointer to the current (the one */
/* we are working with) DosList structure: */
struct DosList *doslist_node;
- - -
/* Get a BCPL pointer (BPTR) to the */
/* first "DosList" node: */
temp_bptr = dos_info_ptr->di_DevInfo;
/* Convert the BPTR into a C pointer: */
first_doslist_node = (struct DosList *)
BADDR( temp_bptr );
/* Start with the first node: */
doslist_node = first_doslist_node;
/* Stay in the loop until all */
/* nodes have been checked: */
while( doslist_node )
{
- - -
/* Examine the node... */
- - -
/* Go to next node: */
/* Get a BPTR to the next node: */
temp_bptr = doslist_node->dol_Next;
/* Convert the BPTR into a C pointer: */
doslist_node = (struct DosList *)
BADDR( temp_bptr );
}
7. When all nodes have been examined you should as quickly as
possible turn on the multitasking by calling the "Permit()"
function.
/* Turn the multitaskin ON again: */
Permit();
easy as pie...
7.6 TO BE CONTINUED...
There are of course a lot of other advanced and interesting
things you can do with AmigaDOS, but that will be added in
coming updates... Remember to pay the registration fee so you
do not miss future updates!
TO BE CONTINUED....(!)